package cn.gyn.gynrpc.core.util;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

@Slf4j
public class TypeUtils {
    /**
     * 类型转换
     * @param origin 获取的原始类型
     * @param returnType 返回的类型
     * @return
     */
    public static Object cast(Object origin, Class<?> returnType) {
        if (origin == null) return null;
        Class<?> originType = origin.getClass();
        //"assignable" 在中文中通常翻译为 "可赋值的"。因此，“isAssignableFrom” 方法可以翻译成“可赋值于”，表示检查一个类是否可以赋值给另一个类。
        //Class<?> class1 = String.class;
        //Class<?> class2 = Object.class;
        //boolean result = class2.isAssignableFrom(class1);
        //在这个例子中，result 将会是 true，因为 Object 类是 String 类的父类，所以 String 类是可以赋值给 Object 类的。
        if (returnType.isAssignableFrom(originType)) {
            return origin;
        }

        //对于想要的是Object对象，但获得的是个HashMap的情况进行转换
        //这行代码的作用是如果 origin 是 HashMap 类的实例，就将 origin 转换为 HashMap 类型并赋值给名为 map 的变量。
        if (origin instanceof HashMap map) {
            JSONObject jsonObject = new JSONObject(map);
            return jsonObject.toJavaObject(returnType);

        }

        //如果要转为返回类型的数组
        if (returnType.isArray()) {
            //如果原始类型是个list，先转为数组
            if (origin instanceof List arr) {
                origin = arr.toArray();
            }
            Class<?> componentType = returnType.getComponentType();
            int length = Array.getLength(origin);
            Object resultArray = Array.newInstance(componentType, length);
            for (int i = 0; i < length; i++) {
                // 通过 componentType.isPrimitive() 判断该类型是否为基本数据类型（primitive type）:
                //整数类型：byte、short、int、long
                //浮点数类型：float、double
                //字符类型：char
                //布尔类型：boolean

                // 或者通过 componentType.getPackageName().startsWith("java") 判断该类型是否属于 Java 内置类型（Java built-in types）:
                //包装类（Wrapper classes）：提供了将基本数据类型包装为对象的功能，例如：Byte、Short、Integer、Long、Float、Double、Character、Boolean。
                //字符串类型：String，虽然不是基本数据类型，但是在 Java 中被广泛使用，并且有特殊的支持和语法糖。
                if (componentType.isPrimitive() || componentType.getPackageName().startsWith("java")) {
                    Array.set(resultArray, i, Array.get(origin, i));
                } else {
                    //处理List[] findUsers(List[] users) 具体case拉代码
                    Object castObject = cast(Array.get(origin, i), componentType);
                    Array.set(resultArray, i, castObject);
                }
            }
            return resultArray;
        }

        //map处理
        if (origin instanceof HashMap map) {
            JSONObject jsonObject = new JSONObject(map);
            return jsonObject.toJavaObject(returnType);
        }

        //List处理
        if (origin instanceof JSONObject jsonObject) {
            return jsonObject.toJavaObject(returnType);
        }

        //Long.class和Long.TYPE的区别：
        //Class<?> longClass = Long.class;
        //Class<?> longTypeClass = Long.TYPE;
        //log.debug(longClass.getName());  // 输出：java.lang.Long
        //log.debug(longTypeClass.getName());  // 输出：long
        //总的来说，Long.class 返回的是Long类的类对象，而 Long.TYPE 返回的是long基本数据类型的类对象。
        if (returnType.equals(Long.class) || returnType.equals(Long.TYPE)) {
            return Long.valueOf(origin.toString());
        } else if (returnType.equals(Integer.class) || returnType.equals(Integer.TYPE)) {
            return Integer.valueOf(origin.toString());
        } else if (returnType.equals(Float.class) || returnType.equals(Float.TYPE)) {
            return Float.valueOf(origin.toString());
        } else if (returnType.equals(Double.class) || returnType.equals(Double.TYPE)) {
            return Double.valueOf(origin.toString());
        } else if (returnType.equals(Byte.class) || returnType.equals(Byte.TYPE)) {
            return Byte.valueOf(origin.toString());
        } else if (returnType.equals(Short.class) || returnType.equals(Short.TYPE)) {
            return Short.valueOf(origin.toString());
        } else if (returnType.equals(Character.class) || returnType.equals(Character.TYPE)) {
            return Character.valueOf(origin.toString().charAt(0));
        } else if (returnType.equals(Boolean.class) || returnType.equals(Boolean.TYPE)) {
            return Boolean.valueOf(origin.toString());
        }
        return null;
    }

    public static Object castMethodResult(Method method, Object data) {
        log.debug("castMethodResult: method = " + method);
        log.debug("castMethodResult: data = " + data);
        Class<?> type = method.getReturnType();
        Type genericReturnType = method.getGenericReturnType();
        //castGeneric（对象, 类型, 泛型），增加泛型的入参就是为了处理map这类的泛型入参
        return castGeneric(data, type, genericReturnType);
    }

    public static Object castGeneric(Object data, Class<?> type, Type genericReturnType) {
        log.debug("castGeneric: data = " + data);
        log.debug("method.getReturnType() = " + type);
        //因为json转换过程会把泛型对象搞丢，比如List<User>里的User?所以这里用了getGenericReturnType获取泛型类型
        log.debug("method.getGenericReturnType() = " + genericReturnType);
        //instanceof的作用是检查变量 data 所引用的对象是否是 JSONObject 类或其子类的实例
        if (data instanceof Map map) { //data是map的情况包括两种，一种是HashMap，一种是JSONObject
            if (Map.class.isAssignableFrom(type)) {
                log.debug(" ======> map -> map");
                Map resultMap = new HashMap();
                log.debug(genericReturnType.toString());
                if (genericReturnType instanceof ParameterizedType parameterizedType) {
                    Class<?> keyType = (Class<?>) parameterizedType.getActualTypeArguments()[0];
                    Class<?> valueType = (Class<?>) parameterizedType.getActualTypeArguments()[1];
                    log.debug("keyType =" + keyType + "|valueType=" + valueType + "|parameterizedType.getActualTypeArguments()=" + Arrays.toString(parameterizedType.getActualTypeArguments()));
                    //entrySet 是用于返回映射的键-值对的 Set 视图
                    map.forEach(
                            (k, v) -> {
                                Object key = cast(k, keyType);
                                Object value = cast(v, valueType);
                                resultMap.put(key, value);
                            }
                    );
                }
                return resultMap;
            }
            //当目标类型是 Map，此时data可能是map也可能是JO
            if (data instanceof JSONObject jsonObject) {
                log.debug(" ===> JSONObject -> Pojo");
                return jsonObject.toJavaObject(type);
            } else if (!Map.class.isAssignableFrom(type)) {
                log.debug(" ===> map -> Pojo");
                return new JSONObject(map).toJavaObject(type);
            } else {
                log.debug(" ===> JSONObject -> ?");
                return data;
            }
        } else if (data instanceof List list) {
            Object[] array = list.toArray();
            if (type.isArray()) {
                //getComponentType获取返回类型里嵌套的类型
                Class<?> componentType = type.getComponentType();

                //因为java的伪泛型导致Object[]与其他任何类型的数组都没有关系，无法进行转换，所以这里需要特别处理，把对象类型的数组array转化为componentType的数组
                Object resultArray = Array.newInstance(componentType, array.length);
                for (int i = 0; i < array.length; i++) {
                    //isPrimitive()用于检查组件类型是否是原始类型，数组是由组件类型和维度组成的。组件类型可以是原始类型（如int、boolean等）或者是引用类型（如String、Object等）
                    //第二个条件判断原始类型的引用类型，包装类（比如：Boolean、Byte）
                    if (componentType.isPrimitive() || componentType.getPackageName().startsWith("java")) {
                        Array.set(resultArray, i, array[i]);
                    } else {
                        Object castObject = TypeUtils.cast(array[i], componentType);
                        Array.set(resultArray, i, castObject);
                    }
                }
                return resultArray;
            } else if (List.class.isAssignableFrom(type)) {
                //如果返回类型为List
                log.debug(" ======> list -> list");
                List<Object> resultList = new ArrayList<>(array.length);
                //获取泛型getGenericReturnType 返回一个 Type 对象，该对象表示了该方法的返回类型，包括了泛型信息。这允许你在运行时获取泛型类型的具体参数类型，比如 List<String> 或 Map<Integer, String>等
                log.debug(String.valueOf(genericReturnType));
                //参数化类型ParameterizedType 是 Java 中的接口，用于表示包含参数化类型（参数化类型，即包含泛型参数的类型，如List<String>、Map<Integer, String>等）的类型。
                if (genericReturnType instanceof ParameterizedType parameterizedType) {
                    Type actualType = parameterizedType.getActualTypeArguments()[0];
                    log.debug(String.valueOf(actualType));
                    for (Object o : array) {
                        resultList.add(TypeUtils.cast(o, (Class<?>) actualType));
                    }
                } else {
                    resultList.addAll(Arrays.asList(array));
                }
                return resultList;
            } else {
                return null;
            }

        } else {
            //类型转换
            return cast(data, type);
        }
    }
}
